Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

modify key event logic to fix ctrl+space not being sent #569

Merged
merged 3 commits into from
Mar 2, 2022

Conversation

tgauth
Copy link
Collaborator

@tgauth tgauth commented Feb 23, 2022

@tgauth tgauth requested a review from bagajjal February 23, 2022 23:17
if (inputRecord.Event.KeyEvent.uChar.UnicodeChar != L'\0') {
// Ctrl+Space & Ctrl+@ generate a NULL character but should still be sent
DWORD dwControlKeyState = inputRecord.Event.KeyEvent.dwControlKeyState;
DWORD dwCtrlPressed = (dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only thing I'm concerned about is the !IsAltPressed() check from the terminal side. Presumably that was there for a reason. @zadjii-msft? Do you recall?

My theory is that it had something to do with AltGr as that can be simulated with a Ctrl and an Alt (https://devblogs.microsoft.com/oldnewthing/20040329-00/?p=40003#:~:text=The%20combination%20Ctrl%2BAlt%20is%20also%20known%20as%20AltGr%2C,keyboards%20there%20are%20only%20two%20%28Normal%20and%20Shift%29.)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(@lhecker might also know as he was in AltGr land for a while)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I've done AltGr handling once.

meme

Copy link

@lhecker lhecker Feb 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change appears to be correct regarding AltGr from what I can tell.
The code that is relevant here are these two places:

I added quite some extensive documentation to that function in the past and maybe it could be helpful here.
While we do have some special AltGr handling (first link) I don't think we'd ever send a client application a null-character for a AltGr sequence, so we don't need to check for that here.


I'm pretty sure that this change doesn't work for Ctrl+Space since it only checks for VkKeyScanW(0).

Additionally when it comes to terminals Ctrl+Alt+@ (but not AltGr+@!) should emit "\x1b[\0" and not "\0".
Basically - according to what I know - Ctrl+2 is just a helper-shortcut in Terminals for Ctrl+@. The proper key-sequence is Ctrl+Shift+2. Back in the dark ages, the Ctrl key used to be a physical (electrical) mask-key which cleared the upper 2 bits of the 7 bit ASCII charset. Since @ is 0b1000000, Ctrl+@ is turned into 0b0000000 - a null byte.
But that means that the meaning of the Alt key is still true: Alt keys induce an escape sequence. Alt+Q is "\x1b[q" and Ctrl+Alt+Shift+2 is "\x1b[\0".

Copy link

@lhecker lhecker Feb 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be more specific, I believe a solution might look like this (includes Ctrl+Space support):

// Returns true if this is a Ctrl+Space or Ctrl+@ combination.
// It assumes that inputRecord->Event.KeyEvent.uChar.UnicodeChar is 0.
static bool
IsNullKeySequence(const INPUT_RECORD* inputRecord)
{
    DWORD state = inputRecord->Event.KeyEvent.dwControlKeyState;
    WORD code = inputRecord->Event.KeyEvent.wVirtualKeyCode;
    return (state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
        && (code == LOBYTE(VkKeyScanW(0)) || code == LOBYTE(VkKeyScanW(L' ')));
}

And then use it as:

if (inputRecord.Event.KeyEvent.uChar.UnicodeChar != L'\0' || IsNullKeySequence(&inputRecord)) {
  • I'm abusing C's support for "short-circuit evaluation"
    By putting function calls into the right-hand-side of boolean conditions we can make sure that they're only called if the other side isn't already "satisfied". Basically with this in place, IsNullKeySequence will only be called if UnicodeChar is actually 0.
  • I'm passing INPUT_RECORD by pointer ("by reference" in other languages), so that we don't incur a copy. GetVTSeqFromKeyStroke should do the same.
  • static because the function is local to this file
  • If this code doesn't compile because of the "bool", replace it with _Bool, which is an official alias and will always work.

This code still doesn't support proper Alt handling, but I'm not sure how important that is for an initial bug fix. The previous code seemingly doesn't support it either after all. 🙂 TIL: In VT mode we send the VT sequences character by character in INPUT_RECORDs, so Ctrl+Alt+@ will not result in a singular null byte anyways.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh, got it. Thanks for the detailed response!

@tgauth tgauth changed the title add check for ctrl+space and ctrl+@ when sending event characters modify key event logic to fix ctrl+space not being sent Feb 24, 2022
@bagajjal bagajjal merged commit a3023c2 into PowerShell:latestw_all Mar 2, 2022
@tgauth tgauth deleted the send-control-space-fix branch March 2, 2022 18:45
@donpellegrino
Copy link

This is a great fix with significant usability consequences, and I am looking forward to the new release. What is the process for getting this fix into an instance of Windows 11 so that Windows Terminal and ssh will work with CTRL+SPACE?

Is there a public status board that shows the flow from GitHub to Windows?

@tgauth
Copy link
Collaborator Author

tgauth commented May 18, 2022

@donpellegrino - we don't have a status board, unfortunately.

We typically wait a bit to receive feedback on a GitHub release before introducing it as a Windows release. There are also Windows schedules that we have to follow. For these reasons, 8.9 is not yet available as a Windows feature-on-demand.

If you would like to use the 8.9.1.0 GitHub release on Windows 11, it is available to download with install instructions here.

@donpellegrino
Copy link

@tgauth - I has been about one year since your patch. Using a fully up-to-date Windows 11 Pro 22H2 (OS build 22621.1194) as of today, February 13, 2023, I still see:

> ssh -V
OpenSSH_for_Windows_8.6p1, LibreSSL 3.4.3

> get-command ssh

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Application     ssh.exe                                            8.6.0.1    C:\Windows\System32\OpenSSH\ssh.exe

I would love to see your work make it through to the production release.

@tgauth
Copy link
Collaborator Author

tgauth commented Feb 13, 2023

@donpellegrino yes, this change will be in the next Windows release (23H2) - https://learn.microsoft.com/en-us/windows/release-health/release-information

OpenSSH 8.9 is currently shipping with Windows Insider Builds.

@Aonodensetsu
Copy link

Aonodensetsu commented Nov 24, 2023

Win11 23H2 still does not have this fix
edit: winget install 'openssh beta' installs it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants